/**
 * Class: LNViews
 *
 */

/**
 * Method: Constructor
 */
function LNViews()
{
	this.files={};
	this.templates={};
	this.options={url_rewrites:{}};
	this.options.do_static=0;
	this.options.do_cache=1;
	this.options.domain="";
	this.load_pending={files:{},callbacks:[]};
}

/**
 * Method: load_file
 *
 */
LNViews.prototype.load_file=function(name,callback)
{
	var t=this;
	if (this.templates[name]) {
		if (callback) callback();
		return;
	}
	var url;
	if (this.options.url_rewrites[name]) {
		url=this.options.url_rewrites[name];
	} else if (this.options.do_static) {
		url=this.options.domain+"/f/"+name+".js";
	} else {
		url=this.options.domain+"/client-side-views/?folder="+name;
	}
	t.load_pending.files[url]=1;
	$.ajax({
		method:"GET",
		url:url,
		async:true,
		cache:this.options.do_cache,
		success: function(data) {
			delete t.load_pending.files[url];
			try {
				eval(data);
			} catch(e) {
				console.log("LNViews.load_file("+name+") - failed");
				console.log(e);
				console.log(data);
			}
			t.templates[name]=1;
			if (callback) callback();
			t.check_load_pending();
		},
		dataType:"html",
		error: function(jqXHR,textStatus,errorThrown) {
			delete t.load_pending.files[url];
			t.check_load_pending();
		}
	});
}

/**
 * Method: after_loaded
 */
LNViews.prototype.after_loaded=function(callback)
{
	var cnt=0;
	for (var k in this.load_pending.files) cnt++;
	if (cnt==0) callback(); else this.load_pending.callbacks.push(callback);
}

/**
 * Method: check_load_pending
 */
LNViews.prototype.check_load_pending=function()
{
	var cnt=0;
	for (var k in this.load_pending.files) cnt++;
	if (cnt) return;
	var arr=this.load_pending.callbacks;
	this.load_pending.callbacks=[];
	for (var i=0;i<arr.length;i++) {
		try {
			arr[i]();
		} catch(e) {
			console.log("LNViews.check_load_pending()",e);
		}	
	}
}

/**
 * Method: safe
 */
LNViews.prototype.safe=function(t)
{
	if (t===undefined) return "--undefined--";
	if (t===null) return "--null--";
	return t.toString().replace(/\&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
}

/**
 * Method: process
 */
LNViews.prototype.process=function(tmplname,cspace)
{
	var tmpl=this.templates[tmplname];
	if (!tmpl) return "<b>[No template "+tmplname+"]</b>";
	if (typeof tmpl != "function") return "<b>[Compilation error "+tmplname+"]</b><br/>"+tmpl;
	var ret;
	try {
		ret=tmpl(cspace,cspace);
	} catch(e2) {
		var r="<pre class='error'>Template: "+tmplname+"\n<h1>Error thrown by exec: "+e2+"</h1>Args:\n";
		console.log("LNViews.process("+tmplname+")",e2);
		r+="</pre>";
		return r;
	}
	return ret;

}



/**
 * Class: LNRR
 */

/**
 * Method: Constructor
 */
function LNRR()
{
	this.site={
		functions:{},
		controllers:{}
	};
	this.fields={};
	this.views=new LNViews();
}

/**
 * Method: controller_configs_join
 *		Controller caller
 *
 */
LNRR.prototype.controller_configs_join=function(config1,config2)
{
	if (!config1) return config2;
	var config={};
	for (var k in config1) config[k]=config1[k];
	for (var k in config2) if (!(k in config)) config[k]=config2[k];
	config["_joined"]=1;
	return config;
}

/**
 * Method: Cview
 *		Render view of given controller
 *
 */
LNRR.prototype.Cview=function()
{
	var c=this._cinfo.config;
	return this.views.process("controllers/"+(c.path||"")+c.name+"/"+(c[this._cinfo.mode+"_view"]||this._cinfo.mode),this);
}

/**
 * Method: C
 */
LNRR.prototype.C=function(controller,mode,config1,nocatch)
{
	var c=this.site.controllers[controller];
	if (!c) {
		return "<b>controller "+controller+" is missing</b>";
	}
	if (c._config.role_code && !this.roles[c._config.role_code]) return "Access denied";
	if (!c[mode]) {
		return "<b>controller "+controller+" exists, but mode "+mode+" is missing</b>";
	}
	var config;
	if (config1 && config1["_joined"]) config=config1; else config=this.controller_configs_join(config1,c._config);
	var cinfo=this._cinfo;
	this._cinfo={controller:controller,mode:mode,config:config};
	var r;
	if (nocatch) {
		r=c[mode].call(this,config);
		this._cinfo=cinfo;
		return r;
	}
	try {
		r=c[mode].call(this,config);
	} catch(e) {
		r="<pre>"+e+"</pre>";
	}
	this._cinfo=cinfo;
	return r;

}

LNRR.prototype.F=function(section,name,arg1,arg2,arg3,arg4)
{
	if (!this.site.functions[section]) throw new Error("<b>[No rr.site.functions."+section+"]</b>");
	if (!this.site.functions[section][name]) throw new Error("<b>[No rr.site.functions."+section+"."+name+"()]</b>");
	return this.site.functions[section][name].call(this,arg1,arg2,arg3,arg4);
}

LNRR.prototype.View=function(tmplname)
{
	return this.views.process(tmplname,this);
}

LNRR.prototype.load_file=function(name,callback)
{
	this.views.load_file(name,callback);
}

LNRR.prototype.exports_add=function(exports)
{
	for (var i=0;i<exports.length;i++) {
		var e=exports[i];
		switch (e._type) {
			case "functions":
				if (!this.site.functions[e._section]) this.site.functions[e._section]={};
				var v=this.site.functions[e._section];
				for (var k in e) if (!k.match(/^_/)) v[k]=e[k];
				break;
			case "controller":
				this.site.controllers[e._config.name]=e;
//				if (!this.site.controllers[e._config.name]) this.site.functions[e._section]={};
				break;
			default:
				console.log("Unknown _type - "+e._type);
		}
	}
}

var lnrr=new LNRR();




/**********************************************************************************/
LNRR.prototype.populate=function()
{

/**
 * Function: escape_text
 */
function escape_text(text)
{
	if (text===undefined || text===null) return "";
	if (typeof (text)=="number") return text.toString();
	text=text.replace(/\\/g,'\\\\');
	text=text.replace(/"/g,'\\"');
	text=text.replace(/'/g,"\\'");
	text=text.replace(/\r?\n/g,'\\n');
	text=text.replace(/\r/g,'\\n');
	return text;
}

/**
 * Function: escape_text2
 */
function escape_text2(text)
{
	if (text===undefined || text===null) return "";
	if (typeof (text)=="number") return text.toString();
	text=text.replace(/&/g,'&amp;');
	text=text.replace(/</g,'&lt;');
	text=text.replace(/>/g,"&gt;");
	return text;
}

/**
 * Function: O_any
 */
function O_any(opt1,groupped,sel)
{
	var r="";
	var cache=[];
	function nbsps(l)
	{
		if (l==0) return "";
		if (!cache[l]) {
			var tmp="";
			for (var j=0;j<l*3;j++) tmp+=String.fromCharCode(160);
			cache[l]=tmp;
		}
		return cache[l];
	}
	function add_options(opt,baselevel)
	{
		for (var i=0;i<opt.length;i++) {
			var name=escape_text2(opt[i].name);
			var id=escape_text(opt[i].id);
			var l=(opt[i].level||1)+baselevel-1;
			r+='<option value="'+id+'"'+((sel && (id==sel))?" selected":"")+'>'+nbsps(l)+name+'</option>';
		}
	}
	function add_rec(arr,level)
	{
		for (var i=0;i<arr.length;i++) {
			var name=escape_text2(arr[i].label);
			r+='<optgroup label="'+nbsps(level)+name+'">';
			if (arr[i].optgroups) add_rec(arr[i].optgroups,level+1);
			if (arr[i].options) add_options(arr[i].options,level);
			r+='</optgroup>';
		}

	}
	if (groupped) {
		add_rec(opt1,0);
	} else {
		add_options(opt1,0);
	}
	return r;
}


/**
 * Function: locale_load
 *		Loads locale
 *
 * Parameters:
 *		config					- site config or system config
 *		lang typeof String		- language code, i.e. "ru", "en"
 *
 */
function locale_load(config,lang)
{
	if (config.i18n && config.i18n[lang]) return;
	var ret={};
	var f=new fs.File(config.paths.i18n+lang+".js");
	if (f.exists()) {
		var req=require(f.toString());
		ret=req.i18n;
	}
	if (!config.i18n) config.i18n={};
	config.i18n[lang]=ret;
}

lnrr.exports_add([{
	_type:"functions",
	_section:"Views",

	/**
 	 * Function: Views.ADMINGETL
	 */
	ADMINGETL: function(param,value) {
		return value.l10ns[this.l10n.id][param];
	},

	/**
 	 * Function: Views.HRtoCOLS
	 */
	HRtoCOLS: function(value) {
		if (value==null || value==undefined) return '<div class="cols"><div class="cl"></div></div>';
		return '<div class="cols"><div class="col">'+value.replace(/<hr.*?>/ig,'</div><div class="col">')+'</div><div class="cl"></div></div>';
	},

	/**
 	 * Function: Views.JSON
	 */
	JSON:function(value) {
		if (value==undefined) return "undefined";
		return JSON.stringify(value).replace(/<\/script>/g,'</"+"script>').replace(new RegExp(String.fromCharCode(0x2028),"g"),"");
	},

/*	JSON_select:function(param,values) {
		var ret=[];
		if (param) ret.push({id:"",name:""});
		JSON_select_recurse(param,values,ret,1);
		return space.functions.JSON(space,ret);
	},

	JSON_gridrower:function(space,param,values) {
		var ret=[];
		JSON_gridrower_recurse(space,param.split(/,/),values,ret,1);
		return space.functions.JSON(space,ret);
	},*/

	/**
 	 * Function: Views.ADD
	 */
	ADD: function(param,value) {
		return 1*param+1*value;
	},
	
	/**
 	 * Function: Views.SUB
	 */
	SUB: function(param,value) {
		return -1*param+1*value;
	},

	/**
 	 * Function: Views.MUL
	 */
	MUL: function(param,value) {
		return param*value;
	},

	/**
 	 * Function: Views.MUL1
	 */
	MUL1: function(param,value) {
		return param*(value-1);
	},

	/**
 	 * Function: Views.CROP
	 */
	CROP: function (size,text) {
		if (text==null || text==undefined) return "";
		if (typeof text != "string") text=text.toString();
		if (text.length>size) return text.substr(0,size-3)+"...";
		return text;
	},

	/**
 	 * Function: Views.LI
	 */
	LI: function(value) {
		if (value==null || value==undefined) return "";
		if (typeof value!= "string") value=value.toString();
		value=value.replace(/&/g,'&amp;');
		value=value.replace(/</g,'&lt;');
		value=value.replace(/>/g,'&gt;');
		return "<li>"+value.replace(/\n/g,"</li><li>")+"</li>";
	},

	/**
 	 * Function: Views.B
	 */
	B: function(value) {
		if (value==undefined) return "";
		value=value.replace(/&/g,'&amp;');
		value=value.replace(/</g,'&lt;');
		value=value.replace(/>/g,'&gt;');
		value=value.replace(/\n/gi,'<br/>');
		return value;
	},

	/**
 	 * Function: Views.MinusTags
	 */
	MinusTags: function(value) {
		value=value.replace(/&lt;(\/?)([biua]|h\d)&gt;/ig,function(a,p1,p2) { return "<"+p1+p2+">";});
		value=value.replace(/&lt;a\s+href="(\/[^"]*|http:[^"]*)"&gt;/ig,function(a,p1) { return "<a href=\""+p1+"\">";});
		return value;
	},

	/**
 	 * Function: Views.Bminus
	 */
	Bminus: function(value) {
		var r=this.F("Views","B",value);
		return this.F("Views","MinusTags",r);
	},

	/**
 	 * Function: Views.P
	 */
	P: function(value) {
		if (value==undefined) return "";
		value=value.replace(/&/g,'&amp;');
		value=value.replace(/</g,'&lt;');
		value=value.replace(/>/g,'&gt;');
		value=value.replace(/\n/gi,'</p>\n<p>');
		return value;
	},

	/**
 	 * Function: Views.Pminus
	 */
	Pminus: function(value) {
		var r=this.F("Views","P",value);
		return this.F("Views","MinusTags",r);
	},

	/**
 	 * Function: Views.T
	 */
	T: function(value) {
		if (value==undefined) return "";
		value=value.replace(/&/g,'&amp;');
		value=value.replace(/</g,'&lt;');
		value=value.replace(/>/g,'&gt;');
		return value;
	},

	/**
 	 * Function: Views.I
	 */
	I: function(value) {
		if (value==undefined) return "";
		value=value.replace(/&/g,'&amp;');
		value=value.replace(/</g,'&lt;');
		value=value.replace(/>/g,'&gt;');
		value=value.replace(/"/g,'&quot;');
		return value;
	},
	
	/**
 	 * Function: Views.JS
	 */
	JS: function(value) {
		if (value==undefined) return "";
		if (typeof(value)=="string") value=escape_text(value).replace(/(scr)(ipt)/gi,'$1"+"$2');
		return value;
	},

	/**
 	 * Function: Views.DumpierNoPre
	 */
	DumperNoPre: function(value) {
		return this.Dumper(value);
	},
	
	/**
 	 * Function: Views.Dumper
	 */
	Dumper: function(value) {
		return "<pre>"+this.Dumper(value)+"</pre>";
	},
	
	/**
 	 * Function: Views.process
	 */
	process: function(value) {
		if (value==undefined) return "";
		if (value==null) return "";
		return this.view_apply(value);
	},

	/**
 	 * Function: Views.CHK
	 */
	CHK: function(value) {
		return value?" checked":"";
	},

	/**
 	 * Function: Views.O
	 */
	O: function(vals) {
		if (!vals) return "";
		return O_any(vals,0);
	},
	OSEL: function(sel,vals) {
		if (!vals) return "";
		return O_any(vals,0,sel);
	},

	/**
 	 * Function: Views.OGRP
	 */
	OGRP: function(vals) {
		if (!vals) return "";
		return O_any(vals,1);
	},
	
	/**
 	 * Function: Views.L
	 */
	L: function(grp,val,easyDefault) {
		var lang=this.use_language;
		if (!lang && this.site) lang=this.site.language;
		if (!lang) lang=this.system.language;
		if (this.site && (!this.site.i18n || !this.site.i18n[lang])) locale_load(this.site,lang);
		if (!this.system.i18n || this.system.i18n[lang]) locale_load(this.system,lang);

		while (1) {
			if (this.site && this.site.i18n[lang][grp] && this.site.i18n[lang][grp][val]) return this.site.i18n[lang][grp][val];
			if (this.system && this.system.i18n[lang][grp] && this.system.i18n[lang][grp][val]) return this.system.i18n[lang][grp][val];
			if (easyDefault) return val;
			/*if (easyDefault==2 || easyDefault==1) {
				var arr=grp.match(/^(.*)\//);
				if (!arr) return val;
				grp=arr[1];
				easyDefault=3;
			} else {*/
				if (easyDefault==3) return val;
				if (easyDefault==1) return this.F("Views","L","generic",val,2);
				return "[I18N("+lang+") "+grp+"."+val+"]";
		//	}
		}
	},
	
	/**
 	 * Function: Views.preview
	 */
	preview: function(param,value) {
		if (value==null || value==undefined) return "";
		if (param=="" || param==null || param==undefined) return value;
		var arr=value.match(/^(.*)(\.\w+)$/);
		return arr[1]+"-preview"+param+arr[2];
	},
	
	/**
 	 * Function: Views.replace
	 */
	replace: function(param,value) {
		var re=new RegExp(param.source);
		return value.replace(re,param.destination);
	},

	/**
 	 * Function: Views.format
	 */
	format: function(param,value) {
		if (typeof value=="null" || typeof value=="undefined" || (typeof value=="string" && value=="")) return "";
		var val=""+value;
		var arr;
		if (!(arr=val.match(/^(-?)(\d+)((?:\.\d+)?)$/))) return value;
		var sign=arr[1];
		var intpart=arr[2];
		var floatpart=arr[3];
		arr=param.match(/^(\d+)G(\d+)$/);
		var intsize=1*arr[1];
		var floatsize=1*arr[2];
		while (intpart.length<intsize) intpart="0"+intpart;
		var intpart2="";
		while (intpart.length>3) {
			if (intpart2.length) intpart2=" "+intpart2;
			intpart2=intpart.substr(intpart.length-3,3)+intpart2;
			intpart=intpart.substr(0,intpart.length-3);
		}
		if (intpart2.length) intpart2=" "+intpart2;
		intpart2=intpart+intpart2;
		if (floatsize==0) return sign+intpart2;
		var floatpart2=floatpart.replace(/^\./,"");
		if (floatpart2.length>floatsize) {
			floatpart2=floatpart2.substr(0,floatsize);
		} else {
			while (floatpart2.length<floatsize) floatpart2+="0";
		}
		return sign+intpart2+"."+floatpart2;
	},
	
	/**
 	 * Function: Views.translit
	 */
	translit: function(value) {
		throw new Error("TODO");/*
		my ($tmpl,$space,$query,$name)=@_;
	$name=new Unicode::Transliterate(from=>"Any",to=>"Latin")->process($name);
	Encode::_utf8_on($name);
	$name=~s/[šŝ]/sh/g;
	$name=~tr/â/ja/;
	$name=~tr/č/ch/;
	$name=~tr/Â/JA/;
	$name=~tr/Č/CH/;
	$name=~tr/éèžû/eezu/;
	$name=~tr/ÉÈŽÛ/EEZU/;
	return $name;*/
	}
}]);
}

lnrr.populate();
